本文档描述基于Sendbird实现的Web3 DM单聊功能,集成Signal Protocol实现End-to-End Encryption,并支持基于用户AA钱包余额的功能。
graph TB %% 定义节点样式 classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px classDef client fill:#e3f2fd,stroke:#1976d2,stroke-width:2px classDef server fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef blockchain fill:#e8f5e9,stroke:#388e3c,stroke-width:2px classDef middleware fill:#fff3e0,stroke:#ef6c00,stroke-width:2px classDef storage fill:#fce4ec,stroke:#c2185b,stroke-width:2px %% 客户端层 subgraph Client["客户端层"] direction TB UI[用户界面] SignalClient[Signal协议客户端] SendbirdClient[Sendbird客户端] LocalDB[本地存储] UI --> SignalClient UI --> SendbirdClient SignalClient --> LocalDB SendbirdClient --> LocalDB end %% 服务层 subgraph Server["服务层"] direction TB subgraph Core["核心服务"] ChatService[聊天服务] UserService[用户服务] KeyService[key管理服务] RelationService[关系管理服务] end subgraph Cache["缓存层"] Redis[(Redis缓存)] end subgraph Storage["存储层"] SQL[(SQL)] end subgraph Message["消息服务"] SendbirdServer[Sendbird服务] MQ[消息队列] end %% 服务层连接 ChatService --> Redis UserService --> Redis KeyService --> Redis RelationService --> Redis ChatService --> SQL UserService --> SQL KeyService --> SQL RelationService --> SQL Core --> MQ MQ --> SendbirdServer end %% 区块链层 subgraph Blockchain["区块链层"] direction TB ChainListener[链上监听服务] DataWarehouse[数据仓库] BalanceCache[余额缓存] ChainListener --> DataWarehouse ChainListener --> BalanceCache DataWarehouse --> BalanceCache end %% 跨层连接 SignalClient --> KeyService SignalClient --> ChatService SendbirdClient --> SendbirdServer UI --> UserService UI --> RelationService Core --> ChainListener Core --> BalanceCache %% 应用样式 class UI,SignalClient,SendbirdClient,LocalDB client class ChatService,UserService,KeyService,RelationService,Core server class ChainListener,DataWarehouse,BalanceCache blockchain class Redis,MQ middleware
客户端层
服务层
区块链层
sequenceDiagram participant Alice as Alice participant Server as Pulse Server participant Sendbird as Sendbird Service participant Bob as Bob %% Initial Setup Phase rect rgb(240, 248, 255) Note over Bob: Initial Setup Note over Bob: Generate Identity Key Pair (IKB_pub, IKB_priv) Note over Bob: Generate Signed PreKey Pair (SPKB_pub, SPKB_priv) Note over Bob: Generate One-Time PreKey Pairs (OPKB_pub, OPKB_priv) Bob->>+Server: Upload Public Keys Bundle:<br/>1. Identity Public Key (IKB_pub)<br/>2. Signed PreKey (SPKB_pub)<br/>3. Signature = Sign(IKB_priv, Encode(SPKB_pub))<br/>4. One-Time PreKeys (OPKB_pub) Server-->>-Bob: Upload Success end %% Session Establishment Phase rect rgb(255, 248, 240) Note over Alice: Generate Identity Key Pair (IKA_pub, IKA_priv) Note over Alice: Generate Ephemeral Key Pair (EKA_pub, EKA_priv) Alice->>+Server: Request Bob's PreKey Bundle Server-->>-Alice: Return Bundle:<br/>1. IKB_pub<br/>2. SPKB_pub + Signature<br/>3. OPKB_pub (if available) Note over Alice: Verify SPKB_pub signature Note over Alice: X3DH Key Agreement:<br/>1. DH1 = DH(IKA_priv, SPKB_pub)<br/>2. DH2 = DH(EKA_priv, IKB_pub)<br/>3. DH3 = DH(EKA_priv, SPKB_pub)<br/>4. DH4 = DH(EKA_priv, OPKB_pub) [if available]<br/>5. SK = KDF(DH1 || DH2 || DH3 || DH4) end %% Initial Message Phase rect rgb(245, 245, 245) Note over Alice: Encrypt initial message with SK Alice->>+Sendbird: Send initial message:<br/>1. IKA_pub<br/>2. EKA_pub<br/>3. PreKey used identifiers<br/>4. Ciphertext Sendbird-->>-Bob: Deliver initial message Note over Bob: Calculate same SK:<br/>1. DH1 = DH(SPKB_priv, IKA_pub)<br/>2. DH2 = DH(IKB_priv, EKA_pub)<br/>3. DH3 = DH(SPKB_priv, EKA_pub)<br/>4. DH4 = DH(OPKB_priv, EKA_pub) [if used]<br/>5. SK = KDF(DH1 || DH2 || DH3 || DH4) Note over Bob: Delete OPKB_priv if used end %% Bidirectional Communication Phase rect rgb(240, 255, 240) Note over Alice,Bob: Double Ratchet Protocol Note over Bob: Generate new ratchet key pair (RKB_pub, RKB_priv) Bob->>+Sendbird: Send response with RKB_pub Sendbird-->>-Alice: Deliver response Note over Alice: Update ratchet with RKB_pub Note over Alice: Generate new ratchet key pair (RKA_pub, RKA_priv) Alice->>+Sendbird: Send message with RKA_pub Sendbird-->>-Bob: Deliver message Note over Bob: Update ratchet with RKA_pub Note over Alice,Bob: Each message:<br/>1. Generates new key pair<br/>2. Updates ratchet state<br/>3. Provides Perfect Forward Secrecy end %% PreKey Maintenance Phase rect rgb(255, 240, 255) Note over Bob: PreKey Maintenance Bob->>+Server: Query remaining PreKey count Server-->>-Bob: Return count alt Count below threshold Note over Bob: Generate new PreKey pairs Bob->>Server: Upload new PreKey public keys end end
实时监听:
定时查询:
多设备支持主要基于以下原则:
graph TB %% 定义节点样式 classDef default fill:#f9f9f9,stroke:#333,stroke-width:1px classDef device fill:#e3f2fd,stroke:#1976d2,stroke-width:2px classDef server fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px %% 用户A的设备 subgraph UserA[用户A] A1[设备1] A2[设备2] A3[设备3] end %% 服务端 PulseSocial[Pulse Social] Sendbird[Sendbird服务] %% 用户B的设备 subgraph UserB[用户B] B1[设备1] B2[设备2] end %% 连接关系 A1 --> PulseSocial A2 --> PulseSocial A3 --> PulseSocial A1 -.->|WebSocket| Sendbird A2 -.->|WebSocket| Sendbird A3 -.->|WebSocket| Sendbird B1 --> PulseSocial B2 --> PulseSocial B1 -.->|WebSocket| Sendbird B2 -.->|WebSocket| Sendbird %% 应用样式 class A1,A2,A3,B1,B2 device class PulseSocial,Sendbird server
设备注册流程
sequenceDiagram participant Device as 新设备 participant Server as Pulse服务端 participant Sendbird as Sendbird服务 Device->>Server: 请求注册新设备 Note over Device: 生成设备ID和注册ID Note over Device: 生成身份密钥对 Device->>Server: 上传设备信息(deviceRegistration) Server->>Sendbird: 择机创建设备对应的聊天频道 Server-->>Device: 返回注册结果 Note over Device: 存储本地密钥
设备信息收集
密钥管理
设备丢失处理
安全考虑
使用场景:
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 用户ID |
| deviceId | String | 设备ID |
| targetUserId | String | 目标用户ID |
| 返回值 | ChannelInfo | 频道信息响应 |
ChannelInfo 对象字段说明:
{
"applicationId": "Sendbird应用ID",
"channelUrl": "频道URL",
"imUserId": "设备对应的Sendbird用户ID",
"sessionToken": "访问令牌",
"targetImUserId": "目标设备的Sendbird用户ID",
"customType": "频道类型标识",
"metadata": {
"encryptionEnabled": true,
"deviceInfo": {
"deviceId": "目标设备ID(当前激活设备)",
"deviceType": "设备类型"
}
}
}
使用场景:用户在新设备上首次使用应用时,需要注册设备信息和密钥信息。
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 用户ID |
| deviceInfo | DeviceInfo | 设备信息对象 |
| 返回值 | DeviceRegistrationResponse | 设备注册响应 |
DeviceInfo 对象字段说明:
{
"deviceId": "设备唯一标识符",
"deviceType": "设备类型(iOS/Android/Desktop)",
"osVersion": "操作系统版本",
"appVersion": "应用版本号",
"pushToken": "推送通知令牌",
"registrationId": "Signal协议注册ID",
"identityPublicKey": "Identity Public Key"
}
DeviceRegistrationResponse 对象字段说明:
{
"deviceId": "已注册的设备ID",
"registrationStatus": "注册状态",
"keyBundleStatus": "密钥包注册状态",
"linkedDevices": [{
"deviceId": "关联设备ID",
"deviceType": "设备类型",
"lastActiveAt": "最后活跃时间"
}]
}
建立连接
sequenceDiagram participant Device as 发送方设备 participant Server as Pulse服务端 participant Sendbird as Sendbird服务 participant Target as 接收方设备 Device->>Server: getChannelInfo(userId, deviceId, targetId, targetDeviceId) Server-->>Device: 返回频道信息 Device->>Sendbird: 建立WebSocket连接 Target->>Server: getChannelInfo(targetId, targetDeviceId, userId, deviceId) Server-->>Target: 返回频道信息 Target->>Sendbird: 建立WebSocket连接
消息发送流程
实现细节
待确定
sequenceDiagram participant A as 用户A客户端 participant Server as Pulse服务端 participant Sendbird as Sendbird服务 participant B as 用户B客户端 %% 初始化阶段 - 用户A Note over A: 1. 生成身份密钥对 Note over A: 2. 生成签名预密钥 Note over A: 3. 生成一批一次性预密钥 A->>Server: setEcSignedPreKey(accountId, deviceId, signedPreKey) A->>Server: setOneTimeEcPreKeys(accountId, deviceId, preKeys) A->>Server: setOneTimeKemSignedPreKeys(accountId, deviceId, kemPreKeys) %% 初始化阶段 - 用户B Note over B: 1. 生成身份密钥对 Note over B: 2. 生成签名预密钥 Note over B: 3. 生成一批一次性预密钥 B->>Server: setEcSignedPreKey(accountId, deviceId, signedPreKey) B->>Server: setOneTimeEcPreKeys(accountId, deviceId, preKeys) B->>Server: setOneTimeKemSignedPreKeys(accountId, deviceId, kemPreKeys) %% 通信建立阶段 Note over A: 用户A想要和用户B通信 A->>Server: getPreKeys(B的accountId, deviceId) Server-->>A: 返回B的预密钥包(PreKeyBundle) %% 密钥透明度验证 A->>Server: getKeyTransparencyProof(B的accountId) Server-->>A: 返回B的密钥透明度证明 Note over A: verifyKeyTransparency(B的accountId, proof) %% 会话建立 Note over A: 1. 使用X3DH协议建立会话 Note over A: 2. 生成会话密钥 Note over A: 3. 生成消息密钥链 %% 消息发送阶段 Note over A: 1. 使用消息密钥加密消息 Note over A: 2. 更新发送链密钥 A->>Sendbird: 发送加密消息(EncryptedMessage) %% 消息接收阶段 Sendbird-->>B: 推送加密消息 %% 首次接收处理 B->>Server: getKeyTransparencyProof(A的accountId) Server-->>B: 返回A的密钥透明度证明 Note over B: verifyKeyTransparency(A的accountId, proof) Note over B: 1. 使用X3DH协议建立会话 Note over B: 2. 生成会话密钥 Note over B: 3. 生成消息密钥链 Note over B: 4. 使用消息密钥解密消息 Note over B: 5. 更新接收链密钥 %% 预密钥维护 B->>Server: getPreKeyCount(B的accountId, deviceId) Server-->>B: 返回预密钥数量 Note over B: 如果预密钥数量低于阈值 B->>Server: setOneTimeEcPreKeys(accountId, deviceId, newPreKeys) %% 定期密钥更新 Note over A,B: 每个会话的密钥在消息发送过程中都会自动轮换 Note over A,B: 签名预密钥定期更新(如每周) Note over A,B: KEM预密钥定期更新(如每月)
使用场景:当用户A想要与用户B开始加密通信时,需要先获取用户B的 PreKey Bundle,用于建立安全的通信会话。通常在首次通信或会话密钥需要更新时调用。
| 参数 | 类型 | 说明 |
|---|---|---|
| targetIdentifier | ServiceIdentifier | 目标用户的服务标识符,包含身份类型和UUID |
| deviceId | Optional |
设备ID,如果不指定则返回所有设备的 PreKey Bundle |
| 返回值 | GetPreKeysResponse | PreKey Bundle Response |
GetPreKeysResponse 对象字段说明:
{
"identityKey": "bytes", // Identity Public Key
"deviceId": "bytes" // key为设备ID, bid
"preKeys": {
"ecSignedPreKey": { // EC Signed PreKey, required
"keyId": "int",
"publicKey": "bytes", // EC Public Key
"signature": "bytes" // Signature by Identity Key
},
"ecOneTimePreKey": { // EC One-Time PreKey, optional (may be empty if used)
"keyId": "int",
"publicKey": "bytes" // EC Public Key
},
"kemOneTimePreKey": { // KEM One-Time PreKey, returns Last Resort PreKey if no One-Time PreKey available
"keyId": "int",
"publicKey": "bytes", // KEM Public Key
"signature": "bytes" // Signature by Identity Key
}
}
}
}
PreKey Availability:
注意事项:
使用场景:
| 参数 | 类型 | 说明 |
|---|---|---|
| 无 | - | 使用认证信息识别设备 |
| 返回值 | GetPreKeyCountResponse | PreKey Count Response |
GetPreKeyCountResponse 对象字段说明:
{
"ecPreKeyCount": "int", // EC PreKey count
"kemPreKeyCount": "int" // KEM PreKey count
}
使用场景:当用户首次注册设备或 PreKey 数量不足时,客户端会生成一批新的 EC PreKey 并上传到服务器。支持批量设置以提高效率。
| 参数 | 类型 | 说明 |
|---|---|---|
| deviceId | ||
| identityKey | ||
| preKeys | List |
EC PreKey List |
| 返回值 | SetPreKeyResponse | Empty response indicates success |
EcPreKey 对象字段说明:
{
"keyId": "int",
"publicKey": "bytes" // EC Public Key
}
使用场景:用户需要定期更新 EC Signed PreKey 以增强安全性。与 One-Time PreKey 不同,Signed PreKey 可以重复使用,但建议定期轮换(如每周)。
| 参数 | 类型 | 说明 |
|---|---|---|
| deviceId | ||
| identityKey | ||
| signedPreKey | EcSignedPreKey | EC Signed PreKey Object |
| 返回值 | SetPreKeyResponse | Empty response indicates success |
EcSignedPreKey 对象字段说明:
{
"keyId": "int",
"publicKey": "bytes", // EC Public Key
"signature": "bytes" // Signature by Identity Key
}
使用场景:为支持后量子加密,用户需要设置一批 KEM PreKey。这些 PreKey 提供抗量子计算攻击的能力。支持批量设置。
| 参数 | 类型 | 说明 |
|---|---|---|
| deviceId | ||
| identityKey | ||
| preKeys | List |
KEM Signed PreKey List |
| 返回值 | SetPreKeyResponse | Empty response indicates success |
KemSignedPreKey 对象字段说明:
{
"keyId": "int",
"publicKey": "bytes", // KEM Public Key
"signature": "bytes" // Signature by Identity Key
}
注意事项:
使用场景:当用户需要验证其他用户的 Identity Key 是否可信时使用。这通常发生在首次通信或检测到对方 Key 变更时,用于防止中间人攻击。
| 参数 | 类型 | 说明 |
|---|---|---|
| accountId | String | 账户ID,要获取证明的目标用户 |
| 返回值 | KeyTransparencyProof | Key Transparency Proof Object |
KeyTransparencyProof 对象字段说明:
{
"accountId": "账户ID",
"keyHistory": [{
"identityKey": "Identity Public Key",
"timestamp": "使用时间戳"
}],
"proof": {
"merkleRoot": "Merkle Tree Root Hash",
"merkleProof": "Merkle Inclusion Proof",
"signature": "Server Signature"
}
}
使用场景:收到其他用户的 Key Transparency Proof 后,需要验证其有效性。这是确保通信安全的关键步骤,可以检测是否存在恶意的 Key 替换。
| 参数 | 类型 | 说明 |
|---|---|---|
| accountId | String | 账户ID,要验证证明的用户 |
| proof | KeyTransparencyProof | Key Transparency Proof to verify |
| 返回值 | boolean | Verification result: true-valid, false-invalid |
使用场景:用户A要向用户B发送加密消息时调用。消息在客户端使用会话密钥加密后,通过该接口发送给服务器。
| 参数 | 类型 | 说明 |
|---|---|---|
| accountId | String | 接收方账户ID |
| deviceId | int | 接收方设备ID |
| message | EncryptedMessage | 加密后的消息对象 |
| 返回值 | void | 无返回值 |
EncryptedMessage 对象字段说明:
{
"messageId": "Message Unique Identifier",
"senderId": "Sender Account ID",
"senderDeviceId": "Sender Device ID",
"ciphertext": "Encrypted Message Content",
"messageType": "Message Type (Text/Image/File etc.)",
"timestamp": "Sent Timestamp",
"ephemeralKey": "Ephemeral Public Key (if used)",
"messageNumber": "Message Sequence Number (for replay protection)"
}
使用场景:用户B定期检查或实时获取发送给自己的加密消息。获取到的消息需要使用对应的会话密钥在客户端解密。
| 参数 | 类型 | 说明 |
|---|---|---|
| accountId | String | 接收方账户ID |
| deviceId | int | 接收方设备ID |
| 返回值 | List |
加密消息列表 |
以上接口共同构成了完整的端到端加密消息传输体系:
错误处理: 所有接口可能抛出的异常包括:
{
"KeyNotFoundException": "Requested key not found",
"KeyValidationException": "Key validation failed",
"DeviceNotFoundException": "Specified device not found",
"QuotaExceededException": "Quota limit exceeded",
"InvalidParameterException": "Invalid parameters",
"AuthenticationException": "Authentication failed",
"ServerException": "Internal server error"
}
PreKey Quota
{
"maxPreKeysPerDevice": 100, // Maximum PreKeys per device
"minPreKeysThreshold": 20, // Minimum threshold
"batchUploadSize": 50, // Batch upload size
"preKeyTTL": 604800, // PreKey TTL (7 days)
"signedPreKey": {
"rotationInterval": 604800 // Signed PreKey rotation interval (7 days)
}
}
PreKey Status
{
"AVAILABLE": "Available",
"USED": "Used",
"EXPIRED": "Expired"
}
客户端主动管理机制*
服务端职责
PreKey Distribution Flow
sequenceDiagram participant A as Sender participant Server as Key Server participant B as Receiver B->>B: Generate PreKeys B->>Server: Upload PreKey Bundle A->>Server: Request B's PreKey alt Available One-Time PreKey Server-->>A: Return One-Time PreKey Bundle Server->>Server: Mark PreKey as used else One-Time PreKeys exhausted Server-->>A: Return Signed PreKey Bundle end B->>Server: Query PreKey count Server-->>B: Return available count Note over B: If count below threshold B->>B: Generate new PreKeys B->>Server: Upload new PreKey Bundle
Key Generation Rules
PreKey Exhaustion Handling
Normal Mode: Using One-Time PreKey
Fallback Mode: Using Signed PreKey
Emergency Mode: Device Offline
Security Considerations:
ChatItem 对象字段说明:
{
"id": "聊天项ID",
"chatType": "聊天类型(GROUP/PRIVATE)",
"channelUrl": "Sendbird频道URL",
"name": "显示名称",
"profileUrl": "头像URL",
"backdropUrl": "背景图URL",
"pinned": "是否置顶",
"latestMessageId": "最新消息ID",
"latestMessageTime": "最新消息时间",
"unreadCount": "未读消息数",
"status": "状态(ACTIVE/ARCHIVED)",
"metadata": {
"groupInfo": { // 群聊特有字段
"managerUserId": "管理员用户ID",
"memberCount": "成员数量",
"dayAllowance": "日限额",
"assetAmount": "资产金额",
"groupCategory": "群组类别",
"chainName": "链名称",
"tokenAddress": "代币地址",
"joinConditions": "加入条件",
"supplier": "供应商"
},
"privateInfo": { // 单聊特有字段
"targetUserId": "目标用户ID",
"encryptionEnabled": true,
"followStatus": "关注状态"
}
}
}
使用场景:
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 用户ID |
| filter | ChatFilter | 过滤条件 |
| 返回值 | ChatListResponse | 聊天列表响应 |
ChatFilter 对象字段说明:
{
"chatTypes": ["GROUP", "PRIVATE"],
"status": ["ACTIVE", "ARCHIVED"],
"showHidden": false
}
ChatListResponse 对象字段说明:
{
"items": [ChatItem]
}
使用场景:更新聊天列表中的项目属性,如置顶、隐藏等。
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 用户ID |
| chatId | String | 聊天项ID |
| updates | ChatItemUpdates | 更新内容 |
| 返回值 | boolean | 更新结果 |
ChatItemUpdates 对象字段说明:
{
"pinned": "是否置顶",
"hidden": "是否隐藏",
"status": "状态(ACTIVE/ARCHIVED)"
}
| 字段名 | 类型 | 说明 | 索引 |
|---|---|---|---|
| id | bigint | 主键 | PK |
| user_id | varchar(64) | 发起方用户ID | IDX |
| target_user_id | varchar(64) | 接收方用户ID | IDX |
| relation_status | varchar(20) | 关系状态(FOLLOWING/BLOCKED/REPORTED) | - |
| created_at | timestamp | 创建时间 | - |
| updated_at | timestamp | 更新时间 | - |
| metadata | jsonb | 扩展信息 | - |
联合唯一索引: (user_id, target_user_id)
metadata字段示例:
{
"blockInfo": {
"reason": "封禁原因",
"blockedAt": "封禁时间",
"expireAt": "封禁过期时间(可选)",
"sendbirdChannelStatus": "频道状态"
},
"reportInfo": {
"reason": "举报原因",
"reportedAt": "举报时间",
"spamType": "垃圾信息类型",
"chatId": "相关聊天室ID",
"evidenceUrls": ["证据图片/视频URL"]
},
"followInfo": {
"isFollowBack": "是否互相关注",
"lastInteractionAt": "最后互动时间",
"chatPreference": "聊天偏好设置"
}
}
| 字段名 | 类型 | 说明 | 索引 |
|---|---|---|---|
| user_id | varchar(64) | 用户ID | PK |
| following_count | int | 关注数 | - |
| followers_count | int | 粉丝数 | - |
| mutual_count | int | 互关数 | - |
| blocked_count | int | 封禁数 | - |
| reported_count | int | 举报数 | - |
| updated_at | timestamp | 更新时间 | - |
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 当前用户ID |
| targetUserId | String | 目标用户ID |
| 返回值 | FollowResponse | 关注结果响应 |
FollowResponse 对象字段说明:
{
"followStatus": "关注状态(FOLLOWING/BLOCKED)",
"timestamp": "关注时间",
"metadata": {
"isFollowBack": "是否互相关注"
}
}
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 当前用户ID |
| targetUserId | String | 目标用户ID |
| 返回值 | boolean | 取消关注结果 |
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 当前用户ID |
| targetUserId | String | 目标用户ID |
| 返回值 | RelationshipInfo | 关系信息 |
RelationshipInfo 对象字段说明:
{
"followStatus": "关注状态",
"chatStatus": "聊天状态",
"lastInteractionAt": "最后互动时间",
"blockStatus": "拦截状态"
}
使用场景:
| 参数 | 类型 | 说明 |
|---|---|---|
| keyword | String | 搜索关键词 |
| filter | UserSearchFilter | 搜索过滤条件 |
| pageSize | int | 分页大小 |
| cursor | String | 分页游标 |
| 返回值 | UserSearchResponse | 用户搜索结果 |
UserSearchFilter 对象字段说明:
{
"followStatus": ["FOLLOWING", "FOLLOWERS", "MUTUAL"]
}
默认排序规则:
关系存储 在user_relationships表
封禁用户接口 (blockUser)
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 当前用户ID |
| targetUserId | String | 目标用户ID |
| reason | String | 封禁原因(可选) |
| 返回值 | BlockResponse | 封禁结果响应 |
BlockResponse 对象字段说明:
{
"status": "封禁状态(SUCCESS/FAILED)",
"timestamp": "操作时间",
"metadata": {
"chatRoomStatus": "聊天室状态",
"sendbirdStatus": "Sendbird频道状态"
}
}
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 举报者用户ID |
| targetUserId | String | 被举报用户ID |
| chatId | String | 聊天室ID |
| reason | String | 举报原因 |
| 返回值 | ReportResponse | 举报结果响应 |
ReportResponse 对象字段说明:
{
"status": "举报状态",
"timestamp": "操作时间"
}
sequenceDiagram participant User as 用户 participant Server as 服务端 participant Sendbird as Sendbird服务 %% 封禁流程 User->>Server: blockUser(userId, targetId) Server->>Server: 更新关系状态为BLOCKED Server->>Sendbird: 设置频道禁言(如果频道存在) Server-->>User: 返回封禁结果 %% 举报流程 User->>Server: reportSpam(userId, targetId) Server->>Server: 更新关系状态为REPORTED Server->>Sendbird: 设置频道禁言(如果频道存在) Server-->>User: 返回举报结果
{
"USER_ALREADY_BLOCKED": "用户已被封禁",
"INVALID_BLOCK_REQUEST": "无效的封禁请求",
"REPORT_ALREADY_SUBMITTED": "已提交过举报",
}
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 用户ID |
| chatId | String | 聊天ID |
| visibility | ChatVisibility | 可见性设置 |
| 返回值 | boolean | 更新结果 |
ChatVisibility 对象字段说明:
{
"isVisible": "是否可见",
"archiveReason": "归档原因"
}
flowchart LR %% 设置图表方向为左到右,使布局更紧凑 A[发送消息] --> B{有钱包?} B -->|否| C[提示创建] B -->|是| D{接收方?} D -->|是| E[无限制] D -->|否| F{检查条件} F --> G{双向关注?} G -->|是| E F --> H{已回复?} H -->|是| E F --> I{已付费?} I -->|是| J[允许发送] I -->|否| K[提示付费]
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 发送方用户ID |
| targetUserId | String | 接收方用户ID |
| 返回值 | MessagePermissionResponse | 权限检查结果 |
MessagePermissionResponse 对象字段说明:
{
"canSend": "是否可发送",
"reason": "限制原因",
"requiredPulseAmount": "需要支付的Pulse数量",
"currentStatus": {
"hasWallet": "是否有钱包",
"isReceiver": "是否为接收方",
"isMutualFollow": "是否双向关注",
"hasReply": "是否有回复",
"pulsePaid": "已支付Pulse数量"
}
}
| 参数 | 类型 | 说明 |
|---|---|---|
| userId | String | 用户ID |
| filter | TransactionFilter | 过滤条件 |
| pageSize | int | 分页大小 |
| cursor | String | 分页游标 |
| 返回值 | PulseTransactionResponse | 交易记录响应 |
TransactionFilter 对象字段说明:
{
"startTime": "开始时间",
"endTime": "结束时间",
"types": ["PAID_MESSAGE", "REWARD", "OTHER"],
"direction": ["DEBIT", "CREDIT"]
}
PulseTransactionResponse 对象字段说明:
{
"transactions": [{
"id": "交易ID",
"timestamp": "交易时间",
"category": "交易类别",
"amount": "数量",
"direction": "收支方向",
"details": {
"messageId": "消息ID(如果是消息付费)",
"targetUser": {
"userId": "目标用户ID",
"nickname": "目标用户昵称"
},
"description": "详细描述"
}
}],
"nextCursor": "下一页游标"
}
graph TD A[定时任务] --> B{是否活跃用户?} B -->|是| C[链上实时监听] B -->|否| D[数据仓库查询] C --> E[更新余额缓存] D --> E